package com.yequan.mybatisframework.sqlsession;

import com.yequan.mybatisframework.config.*;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;


public class BaseExecutor implements Executor {

	@Override
	public <T> List<T> query(MappedStatement mappedStatement, Configuration configuration, Object paramObj) {
		List<Object> results = null;
		try {
			// 1.获取连接
			Connection connection = getConnection(configuration);
			// 2.获取sql语句(重点)
			SqlSource sqlSource = mappedStatement.getSqlSource();
			BoundSql boundSql = sqlSource.getBoundSql();
			String sql = boundSql.getSql();
			// 3.创建statement
			String statementType = mappedStatement.getStatementType();

			// StatementHandler statementHandler = new
			// RoutingStatmentHandler(mappedStatement);
			statementType = statementType == null || statementType.equals("") ? "prepared" : statementType;
			if ("prepared".equals(statementType)) {
				PreparedStatement statement = createStatement(connection, sql);
				paramize(statement, paramObj, boundSql, mappedStatement);
				// 4.执行statement
				ResultSet resultSet = statement.executeQuery();
				// 5.处理结果映射
				results = handleResult(resultSet, mappedStatement.getResultTypeClass());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return (List<T>) results;
	}

	private List<Object> handleResult(ResultSet resultSet, Class<?> resultTypeClass) throws Exception {
		List<Object> results = new ArrayList<Object>();

		// 每次遍历是一行
		while (resultSet.next()) {
			Object newInstance = resultTypeClass.newInstance();
			ResultSetMetaData metaData = resultSet.getMetaData();
			int columnCount = metaData.getColumnCount();

			// 获取每一列的信息
			for (int i = 0; i < columnCount; i++) {
				// 获取列的名称
				String columnName = metaData.getColumnName(i + 1);
				// 根据列的名称去反射设置对象的属性
				Field field = resultTypeClass.getDeclaredField(columnName);
				field.setAccessible(true);
				field.set(newInstance, resultSet.getObject(i + 1));
			}

			results.add(newInstance);
		}
		return results;
	}

	public void paramize(PreparedStatement preparedStatement, Object paramObj, BoundSql boundSql,
			MappedStatement mappedStatement) {
		try {
			// 设置参数，第一个参数为 sql 语句中参数的序号（从 1 开始），第二个参数为设置的

			List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();

			Class<?> parameterTypeClass = mappedStatement.getParameterTypeClass();

			// 此次可以使用设计模式中的策略模式进行改造
			if (parameterTypeClass == Integer.class) {
				preparedStatement.setInt(1, (int) paramObj);
			} else {
				// POJO类型
				for (int i = 0; i < parameterMappings.size(); i++) {
					ParameterMapping parameterMapping = parameterMappings.get(i);
					String name = parameterMapping.getName();

					Field field = parameterTypeClass.getDeclaredField(name);
					field.setAccessible(true);
					Object value = field.get(paramObj);

					preparedStatement.setObject(i + 1, value);
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public PreparedStatement createStatement(Connection connection, String sql) {
		try {
			// 获取预处理 statement
			PreparedStatement preparedStatement = connection.prepareStatement(sql);
			return preparedStatement;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	private Connection getConnection(Configuration configuration) {
		try {
			DataSource dataSource = configuration.getDataSource();
			return dataSource.getConnection();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

}
